﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Utilities.Shell
{
    public class Scope : IRunnable
    {
        public Shell Shell { get; private set; }
        public Scope Parent { get; private set; }
        public bool Exited { get; private set; }

        public List<Variable> Variables
        {
            get
            {
                if (Parent == null)
                    return LocalVariables;
                else
                    return LocalVariables.Union(Parent.Variables).ToList();
            }
        }
        public List<Variable> LocalVariables { get; private set; }

        public List<IRunnable> Instructions { get; private set; }

        private ComposedInstruction currentComposedInstruction = null;
        private Scope subScope = null;
        private int subScopeLevel = 0;

        public Scope(Shell shell) : this(shell, null) { }
        public Scope(Shell shell, Scope parent)
        {
            Shell = shell;
            Parent = parent;
            Exited = false;

            LocalVariables = new List<Variable>();
            Instructions = new List<IRunnable>();
        }

        public void Add(string instruction)
        {
            instruction = instruction.Trim();

            if (instruction == ")")
            {
                subScopeLevel--;
                if (subScopeLevel == 0)
                    Instructions.Add(currentComposedInstruction);
            }

            if (subScopeLevel > 0)
                subScope.Add(instruction);

            if (instruction != ")" && subScopeLevel == 0)
            {
                if (instruction.EndsWith("("))
                {
                    currentComposedInstruction = new ComposedInstruction(this, instruction);
                    subScope = currentComposedInstruction.Instructions.Last() as Scope;
                }
                else if (instruction.Contains(">"))
                    Instructions.Add(new ComposedInstruction(this, instruction));
                else
                    Instructions.Add(new Instruction(this, instruction));
            }

            if (instruction.EndsWith("("))
                subScopeLevel++;
        }
        public void Run(string replacement)
        {
            foreach (IRunnable instruction in Instructions)
            {
                instruction.Run(replacement);
                if (Exited)
                    break;
            }
            Instructions.Clear();
        }

        public void Exit()
        {
            Exited = true;
        }
    }
}
